/*->c.vxbuff */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <ctype.h>
#include <time.h>

#include "h.os"
#include "h.wimp"
#include "h.bbc"
#include "h.flex"
#include "h.akbd"


#include "h.def"
#include "h.key"
#include "h.wos"
#include "h.main"
#include "h.ram"
#include "h.mym"
#include "h.trans"
#include "h.file"
#include "h.serial"
#include "h.term"
#include "h.xext"

#include "h.vxdef"
#include "h.vxterm"

#include "h.vxwimp"
#include "h.vxmenu"
#include "h.vxsend"
#include "h.mxterm"

#include "h.vxbuff"




/***************************************************************************/
/*
 Code to handle VX buffers
*/
/*****************************************************************************/


int vxcbuff;                  /* number of selected buffer */
int vxnb;                     /* number of current buffer  */
int vxnobuffers;              /* number of buffers in use  */


vxbuffstr vxbuff[MAXBUFF];    /* viewdata buffer headers */


/*****************************************************************************/

/* saves one frame from a vsc buffer */

int saveframesub(FILE * fp,vxscreen * vsc,int framesize)
{
 int i;

 if(framesize==CEPT2FF)   rwrite(vsc->tcbuf[vsc->start],framesize,1,fp);
 else
 for(i=0;i<framesize;i++) rputc(vsc->tcbuf[vsc->start][i],fp);

 return(1);
}


/* saves the current screen as a frame file */

int savecframe(char * filename)
{
 FILE * fp;
 int code;

 vxinitblock(vscr);

 if((fp=ropen(filename,"wb"))==NULL) return(0);

 code=saveframesub(fp,vscr,vxframesize);

 savetypeclose(fp,filename);

 return(code);
}



int vxsavecurrentframe(char * name,int type)
{
 int code;
 int frameformat;

 code=0;

 if(minitel && type==CEPT2) return(savecframe(name));
 else
 if(!minitel && (type==FRAME || type==CEPT3))
 {
  frameformat=vxhearsayff;
  vxhearsayff=type==FRAME;
  setvxframesize();
  code=savecframe(name);
  vxhearsayff=frameformat;
  setvxframesize();
 }

 return(code);
}



/*****************************************************************************/


/* saves one frame from a vsc buffer as text */

static int savetexframesub(FILE * fp,int * p,char * q,int size)
{
 int  imy;
 int  imx;
 int  grf;
 int  bfl;
 int  c;
 char buff[42];

 if(size==CEPT2FF && !p) p=(int*)q;

 for(imy=0;imy<24;imy++)   /* line loop */
 { 
  grf=0;
  bfl=0;

  for(imx=0;imx<40;imx++)
  {
   if(p) c=*p++;
   else  c=*q++;

   if(size==CEPT2FF)               /* Minitel */
   {
    c&=VXCMASK;
   /* c+=32;
    if(c>127) c=32;  */
    c=mxisomap[c+32];
   }
   else                            /* Viewdata format */
   {
    if(c>128 && c<136) grf=0;
    else
    if(c>144 && c<152) grf=1;
    c&=0x7F;
    if(c<32 || c==127 || (grf && (c<64 || c>95))) c=32;
   }

   if(c!=32) bfl=imx+1;
   buff[imx]=c;
  }

  buff[bfl++]=LF;
  rwrite(buff,bfl,1,fp);
 }

 return(1);
}


/* saves the current screen as a text file */

int savectexframe(char * filename)
{
 FILE * fp;
 int code;

 if((fp=ropen(filename,"wb"))==NULL) return(0);

 code=savetexframesub(fp,vscr->tcbuf[vscr->start],NULL,vxframesize);

 savetypeclose(fp,filename);

 return(code);
}


                                    
int savetexbuffsub(char * filename,int i)
{
 FILE * fp;
 int code=0;
 int frame;
 char * p;

 if((fp=ropen(filename,"wb"))==NULL) return(0);

 p=vxbuff[i].data;

 for(frame=0;frame<vxbuff[i].noframes;frame++)
 {
  code=savetexframesub(fp,NULL,p,vxbuff[i].framesize);
  p+=vxbuff[i].framesize;
  if(!code) break;
 }

 savetypeclose(fp,filename);

 return(code);
}



int savetexbuff(char * filename)
{
 return(savetexbuffsub(filename,vxcbuff));
}



int savetexmbuff(char * filename)
{
 return(savetexbuffsub(filename,vxbmenu));
}


/****************************************************************************/


int getvxbuff(int window)   /* set vxnb current window */
{
 int i;
 for(i=0;i<MAXBUFF;i++) if(vxbuff[i].handle==window) break;
 if(i==MAXBUFF) return(0); /* not a buffer window */
 vxnb=i;
 return(1);
}


int getvxtools(int window)   /* set vxnb current from tools window */
{
 int i;
 for(i=0;i<MAXBUFF;i++) if(vxbuff[i].thandle==window) break;
 if(i==MAXBUFF) return(0); /* not a buffer window */
 vxnb=i;
 return(1);
}



int getnewvxb(void)         /* returns handle for new buffer */
{
 int i;

 for(i=0;i<MAXBUFF;i++)
 {
  if(!vxbuff[i].inuse) break;
 }

 return(i);
}




/* generates a unique new name */

static char * vxbnewname(void)
{
 static char name[16];

 int i;
 int j;

 for(i=1;i<=MAXBUFF;i++)
 {
  sprintf(name,"%s%d",transtoken("VXBF00"),i);

  for(j=0;j<MAXBUFF;j++)
  {
   if(vxbuff[j].inuse && !cstrcmp(name,leaf(vxbuff[j].name))) break;
  }

  if(j==MAXBUFF) break;
 }
 return(name);
}


/* return 1 if can extend buffer or 0 */

int vxbsize(int i,int n)
{
 if(vxbuff[i].data)
 {
  if(!flex_extende((flex_ptr)&vxbuff[i].data,vxbuff[i].framesize*n)) return(0);
 }
 else
 {
  if(!flex_alloce((flex_ptr)&vxbuff[i].data,vxbuff[i].framesize*n)) return(0);
 }

 vxbuff[i].noframes=n;
 return(1);
}



/* creates buffer i with n frames */

static int vxbcreate(int i,int n,int type)
{
 vxbuff[i].framesize=type;
 vxbuff[i].current=0;
 vxbuff[i].modded=0;
 vxbuff[i].handle=0;
 if(vxbsize(i,n))
 {
  vxbuff[i].inuse=1;
  vxnobuffers++;
  return(1);
 }
 else
  return(0);
}


/* trashes buffer i */

void vxbtrash(int i)
{
 flex_free((flex_ptr)&vxbuff[i].data);
 vxbuff[i].inuse=0;
 vxnobuffers--;
}




/* takes data from screen, and write to data pointer */

static void vxrevtranframe(vxscreen * vsc,char * data,int framesize)
{
 int * p;
 int * q;

 p=vsc->tcbuf[vsc->start];
 q=p+framesize;
 if(framesize==HEARSAYFF) while(p<q) *data++=*p++|0x80;
 else
 if(framesize==CEPT3FF)   while(p<q) *data++=*p++;
 else
 if(framesize==CEPT2FF)
 {
  q=p+(framesize/sizeof(int));
  while(p<q)
  {
   *((int*)data)=*p++;
   data+=sizeof(int);
  }
 }
}



void vxbtranframe(vxscreen * vsc,char * data,int framesize)
{
 int * p;
 int * q;
 int   y;

 p=vsc->tcbuf[vsc->start];
 q=p+framesize;

 if(framesize==HEARSAYFF)
 {
  while(p<q)
  {
   y=*data++;
   if(y>=160) y&=0x7F;
   *p++=y;
  }
 }
 else
 if(framesize==CEPT3FF)   while(p<q) *p++=*data++;
 else
 if(framesize==CEPT2FF)
 {
  q=p+(framesize/sizeof(int));
  while(p<q)
  {
   *p++=*((int*)data);
   data+=sizeof(int);
  }
 }

 for(y=0;y<vsc->height;y++)
 {
  vsc->rlo[y]=vsc->rhi[y]=0;
  vsc->flo[y]=vsc->fhi[y]=0;
  vsc->attr[y]=VXASH;
 }


 if(framesize==HEARSAYFF || framesize==CEPT3FF)
 {
  for(y=0;y<vsc->height;y++) convertline(vsc,y);
 }
 else
 {
  mxconvertall(vsc);
 }

 vxpendredraw=0;
}



/* manages the transfer of the current screen from the data buffer */
/* to the screen buffer, and then to the display area              */

void vxbsetscreen(int i)
{
 if(vxbuff[i].vsc)
 {
  if(vxbuff[i].noframes)
  {
   vxbtranframe(vxbuff[i].vsc,vxbuff[i].data+
                vxbuff[i].current*vxbuff[i].framesize,vxbuff[i].framesize);
  }
  else
  {
   viewclslo(vxbuff[i].vsc);
  }
 }
}




/* updates screen with window refresh */

void vxbsetscreenr(int i)
{
 if(vxbuff[i].handle)
 {
  vxbsetscreen(i);
  refreshwindow(vxbuff[i].handle);
 }
}



int vxcframenumber(int i)
{
 return(vxbuff[i].current+(vxbuff[i].noframes>0));
}



static char kicons[6]={18,62,94,19,63,87}; 



void vxbwritekeypad(int i)
{
 int fn;
 int j;
 fn=vxcframenumber(i);
 for(j=3;j<6;j++) writeiconf(whandle[KEYPAD],kicons[j],"%d",fn);
}



/* called when we change current buffer settings */

void vxbupdatecurrent(void)
{
 int  handle;
 int  i;
 char temp[16];

 handle=whandle[KEYPAD];

 if(handle)
 {
  if(vxcbuff==-1)
  {
   for(i=0;i<6;i++) writeicon(handle,kicons[i],"");
  }
  else
  {
   strcpy(temp,vxbuff[vxcbuff].wname);
   i=strlen(temp);
   if(i>2 && temp[i-1]=='*' && temp[i-2]==' ') temp[i-2]=0;
   for(i=0;i<3;i++) writeicon(handle,kicons[i],temp);
   vxbwritekeypad(vxcbuff);
  }
 }
}



/* called when a given buffer is changed */

void vxbwritecurrent(int i)
{
 if(vxbuff[i].thandle) writeiconf(vxbuff[i].thandle,1,"%d",vxcframenumber(i));
 if(i==vxcbuff && vxkeypad && whandle[KEYPAD]) vxbwritekeypad(i);
}




/* moves buffer forward one frame */

void vxbforward(int i)
{
 if(i<0) return;
 if(vxbuff[i].noframes<=1) return;
 vxbuff[i].current++;
 if(vxbuff[i].current>=vxbuff[i].noframes) vxbuff[i].current=0;
 vxbsetscreenr(i);
 vxbwritecurrent(i);
}


/* moves buffer backward one frame */

void vxbbackward(int i)
{
 if(i<0) return;
 if(vxbuff[i].noframes<=1) return;
 vxbuff[i].current--;
 if(vxbuff[i].current<0) vxbuff[i].current=vxbuff[i].noframes-1;
 vxbsetscreenr(i);
 vxbwritecurrent(i);
}


void vxcbforward(void)
{
 vxbforward(vxcbuff);
}

void vxcbbackward(void)
{
 vxbbackward(vxcbuff);
}


/*****************************************************************************/

/* opens the tools pane */

void vxbtoolsopen(int i,wimp_openstr * open)
{
 wimp_openstr o;
 int w,h;

 getw(vxbuff[i].thandle);
 w=x1-x0;
 h=y1-y0;

 x0=open->box.x0-w-2*deltax;
 if(x0<0)
 {
  if(x0>-w) x0=0;
  else      x0+=w;
 }
 x1=x0+w;
 y1=open->box.y1; 
 y0=y1-h;

 o.w=vxbuff[i].thandle;
 o.box.x0=x0;
 o.box.y0=y0;   
 o.box.x1=x1;
 o.box.y1=y1;
 o.x=scx;       
 o.y=scy;
               
 o.behind=open->behind;

 wimp_open_wind(&o);
}



/* called by wimps to open buffer window */
/* we open tools pane on top             */

void vxblowopen(int i,wimp_openstr * o)
{
 int left;

 clipwindow(o,1);

 if(vxbuff[i].tools)
 {
  getw(vxbuff[i].handle);

  left=(x0>o->box.x0);

  getw(vxbuff[i].thandle);
  if(!(wflags & 0x10000) || left) vxbtoolsopen(i,o);
  if(bhandle==o->behind) o->behind=vxbuff[i].thandle;

  wimp_open_wind(o);

  if(o->behind==-2)
  {
   getw(vxbuff[i].handle);
   o->behind=bhandle;
  }

  vxbtoolsopen(i,o);
 }
 else
  wimp_open_wind(o);

 if(vxbuff[i].vsc->zoom.var) vxsetvarzoomlo(vxbuff[i].handle,vxbuff[i].vsc);
}



void vxbpopup(int i)
{
 wimp_openstr o;
 vxscreen *   vsc;

 vsc=vxbuff[i].vsc;
 o.w=vxbuff[i].handle;
 o.box.x0=128+(i % 5)*vscrlbar;
 o.box.x1=o.box.x0+VXDX*40;
 o.box.y1=screeny-2*hscrlbar-(i % 4)*hscrlbar;
 o.box.y0=o.box.y1-VXDY*24;
 o.y=0;
 o.x=0;
 o.behind=-1;

 vxblowopen(i,&o);
}


/* opens a window on buffer i */


void vxbopen(int i)
{
 wimp_wind * wp;
 vxscreen  * vsc;

 if(i<0) return;

 if(vxbuff[i].handle)
 {                              /* bring window forward */
  forward(vxbuff[i].handle);
  if(vxbuff[i].thandle) forward(vxbuff[i].thandle);
  return;
 }

 if(!vxbuff[i].vsc)
  if(!flex_alloce((flex_ptr)&vxbuff[i].vsc,sizeof(vxscreen))) return;

 vsc=vxbuff[i].vsc;

 vsc->zoom=vxbdefz;
 vxbuff[i].tools=vxdeftools;

 vsc->pixelgrid=0;
 vsc->flashphase=0;
 vsc->height=24;
 vsc->start=0;

 vxsetscales(vsc);

 vxbsetscreen(i);

 wp=windpoi[VDATA];

 wp->titleflags|=wimp_INDIRECT;

 wp->title.indirecttext.buffer=vxbuff[i].wname;
 wp->title.indirecttext.bufflen=WBUFFNAMELEN;
 wp->title.indirecttext.validstring=NULL;

 wimp_create_wind(wp,&vxbuff[i].handle);

 wp->titleflags^=wimp_INDIRECT;
 strcpy(wp->title.text,transtoken("VDATA"));

 if(vxbuff[i].tools)
 {
  wp=windpoi[BTOOLS];
  wimp_create_wind(wp,&vxbuff[i].thandle);
  vxbwritecurrent(i);
 }

 extent(vxbuff[i].handle,0,-VXEDY*24,VXEDX*40,0);
 vxbpopup(i);
}



/* closes window on buffer i */

void vxbclose(int i)
{
 flex_free((flex_ptr)&vxbuff[i].vsc);
 
 if(vxbuff[i].handle)
 {
  wimp_close_wind(vxbuff[i].handle);
  vxbuff[i].handle=0;
 }

 if(vxbuff[i].thandle)
 {
  wimp_close_wind(vxbuff[i].thandle);
  vxbuff[i].thandle=0;
 }
}



/* toggle tools on and off */

void vxtoggletools(int i)
{
 wimp_wind * wp;
 wimp_wstate winds;

 if(vxbuff[i].handle)
 {
  if(vxbuff[i].tools)
  {
   vxbuff[i].tools=0;
   wimp_close_wind(vxbuff[i].thandle);
   vxbuff[i].thandle=0;
  }
  else
  {
   wp=windpoi[BTOOLS];
   wimp_create_wind(wp,&vxbuff[i].thandle);
   vxbwritecurrent(i);
   wimp_get_wind_state(vxbuff[i].handle,&winds);
   vxbtoolsopen(i,&winds.o);
   vxbuff[i].tools=1;
  }
 }
}



void vxbmod(int i)
{
 if(vxbuff[i].modded) return;
 strcat(vxbuff[i].wname," *");
 if(vxbuff[i].handle) refreshwindowtitle(vxbuff[i].handle);
 vxbuff[i].modded=1;
}


void vxbsetdeflt(void)
{
 if(vxbuff[vxbmenu].inuse && vxbuff[vxbmenu].vsc)
 {
  vxbdefz=vxbuff[vxbmenu].vsc->zoom;
  vxdeftools=vxbuff[vxbmenu].tools;
 }
}



/****************************************************************************/
/* editing functions */


/* is a frame from the main window compatible with buffer i */

int vxbok(int i,int zero)
{
 if(i>=0 && i<MAXBUFF && (vxbuff[i].noframes || zero) && vxbuff[i].inuse)
 {
  if(vxbuff[i].framesize==CEPT2FF || minitel)
  {
   if(vxbuff[i].framesize==CEPT2FF && minitel) return(1);
  }
  else return(1);
 }
 return(0);
}



/* pastes the current frame from buffer i onto the main window */ 

void vxbpaste(int i)
{
 if(vxbok(i,0))
 {
  vxbtranframe(vscr,vxbuff[i].data+vxbuff[i].current*vxbuff[i].framesize,
                                                     vxbuff[i].framesize);
  refreshwindow(whandle[VDATA]);
 }
}



/* copies the main window onto the end of buffer i */

void vxbcopy(int i)
{
 if(i<0)   /* create a buffer, make current etc. */
 {
  if(!vxnewbuffer(vxbnewname())) return;
  i=vxcbuff;
 }

 if(vxbok(i,1))
 {
  if(vxbsize(i,vxbuff[i].noframes+1))
  {
   vxbuff[i].current=vxbuff[i].noframes-1;
   vxinitblock(vscr);
   vxrevtranframe(vscr,vxbuff[i].data+vxbuff[i].current*vxbuff[i].framesize,
                                                      vxbuff[i].framesize);
   vxbsetscreenr(i);
   vxbwritecurrent(i);
   vxbmod(i);
  }
 }
}


/* does a goto on the current frame in buffer i */

int vxgotoactive;

void vxbgoto(int i)
{
 char * k;
 char   c;
 int    x;
 int    y;
 int    time;

 if(vxbok(i,0) && !vxgotoactive && !minitel)
 {
  vxgotoactive=1;
  vxbpaste(i);

  /* more, much more... */

  /* clever stuff here */

  k=vxbuff[i].data+vxbuff[i].current*vxbuff[i].framesize+25;
 
  c=(*k) & 0x7F;

  if(c < '0' || c > '9')
  {
   errorbox("{VXBF01}"); /* No number on this frame */
  }
  else
  {
   viewline('*');

   for(x=0;x<10;x++)
   {
    c = (*k) & 0x7F; 
    if(c>='0' && c <='9') viewline((* k++) & 0x7F);
    else break;
   }

   x=(*k) & 0x5f;
   if(x>='A' && x<='Z') for(y='A';y<=x;y++) viewline(95);

   time=clock()+500;
   while(clock()<time)
   {
    if(getbyte()==12) 
    {
     viewhome();
     break;
    }
    pollzt();
   }
  }
  vxgotoactive=0;
 }
}



/* trashes the current frame in buffer i */

void vxbdelete(int i)
{
 if(i>=0 && i<MAXBUFF && vxbuff[i].noframes && vxbuff[i].inuse)
 {
  flex_midextend((flex_ptr)&vxbuff[i].data,
          (vxbuff[i].current+1)*vxbuff[i].framesize,-vxbuff[i].framesize);
  if(vxbuff[i].current) vxbuff[i].current--;
  vxbuff[i].noframes--;
  vxbsetscreenr(i);
  vxbwritecurrent(i);
  vxbmod(i);
 }
}



void vxbreplace(int i)
{
 if(vxbok(i,0))
 {
  vxinitblock(vscr);
  vxrevtranframe(vscr,vxbuff[i].data+vxbuff[i].current*vxbuff[i].framesize,
                                                       vxbuff[i].framesize);
  vxbsetscreenr(i);
  vxbmod(i);
 }
}



/* inserts the main window before the current frame in buffer i */

void vxbinsert(int i)
{
 if(vxbok(i,1))
 {
  if(flex_midextend((flex_ptr)&vxbuff[i].data,
                  vxbuff[i].current*vxbuff[i].framesize,vxbuff[i].framesize))
  {
   vxbuff[i].noframes++;
   vxinitblock(vscr);
   vxrevtranframe(vscr,vxbuff[i].data+vxbuff[i].current*vxbuff[i].framesize,
                                                       vxbuff[i].framesize);
   vxbsetscreenr(i);
   vxbwritecurrent(i);
   vxbmod(i);
  }
 }
}



/*****************************************************************************/
/* wimp entry points, vxnb is already set up */


#define RDRAW   0x2



void vxbwredraw(void)
{
 wimp_redrawstr redrawstr;
 int            more;

 redrawstr.w=ewindow;
 
 wimp_redraw_wind(&redrawstr,&more);
 while(more)
 {
  redrawvxsub(&redrawstr,RDRAW,vxbuff[vxnb].vsc);
  wimp_get_rectangle(&redrawstr,&more);
 }
}



void vxbwicon(void)
{
 if(isshift)
 {
  if(buttons==0x100 || buttons==0x1) vxbbackward(vxnb);
  else
  if(buttons==0x400 || buttons==0x4) vxbforward(vxnb);
 }
 else
 {
  switch(buttons)
  {
   case   0x2:             /* click with menu */
              popvxbmain();
              break;

   case   0x1:             /* double click with adjust */
              vxreplytombx(vxbuff[vxnb].vsc,vxbuff[vxnb].handle);
              break;

   case 0x400:             /* single click with select */
              vxsendcursorcode(vxbuff[vxnb].vsc,vxbuff[vxnb].handle);
              break;
  }
 }
}





void vxbtoolsicon(void)
{
 if(buttons==4)
  switch(icon)
  {
   case 0:
          vxbforward(vxnb);
          break;

   case 2:
          vxbbackward(vxnb);
          break;

   case 3:
          vxbgoto(vxnb);
          break;

   case 4:
          vxbpaste(vxnb);
          break;

   case 5:
          vxbdelete(vxnb);
          break;
  }
 else
 if(buttons==1)
  switch(icon)
  {
   case 0:
          vxbbackward(vxnb);
          break;

   case 2:
          vxbforward(vxnb);
          break;

   case 3:
          vxbclose(vxnb);
          vxbgoto(vxnb);
          break;
  }
}




void vxbwclose(void)
{
 vxbclose(vxnb);
}



/* a wimp open event on main buffer window */

void vxbwopen(void)
{
 vxblowopen(vxnb,&wimpevent.data.o);
}




void vxbdozoom(void)
{
 vxmenuzoom(vxbuff[vxbmenu].handle,vxbuff[vxbmenu].vsc);
}


void vxbvarzoom(void)
{
 vxmenuzoom(vxbuff[vxbmenu].handle,vxbuff[vxbmenu].vsc);
 vxvarzoomsub(vxbuff[vxbmenu].handle,vxbuff[vxbmenu].vsc);
}


int vxmaptypetosize(int type)
{
 if(type==FRAME) return(HEARSAYFF);
 else
 if(type==CEPT2) return(CEPT2FF);
 else
                 return(CEPT3FF);
}


int vxmapsizetotype(int size)
{
 if(size==HEARSAYFF) return(FRAME);
 else
 if(size==CEPT2FF)   return(CEPT2);
 else
                     return(CEPT3);
}



int  vxbloadfile(char * name,int type)
{
 FILE * fp;

 int    nread;
 int    nstep=10;
 int    nsize=nstep;
 int    i;
 char   header[16];
 int    fix;

 type=vxmaptypetosize(type);

 for(i=0;i<MAXBUFF;i++)
   if(vxbuff[i].inuse && !cstrcmp(vxbuff[i].name,name)) break;

 if(i<MAXBUFF)
 {
  vxcbuff=vxnb=i;
 }
 else
 {
  if(vxnobuffers>=MAXBUFF)
  {
   errorbox("{VXBF02}"); /* Cannot open another buffer. */
   return(1);
  }

  vxcbuff=vxnb=getnewvxb();

  strcpy(vxbuff[vxnb].name,name);
  strcpy(vxbuff[vxnb].wname,leaf(name));

  if((fp=ropen(name,"rb"))==NULL)
  {
   errorbox("{VXBF03}"); /* Cannot open file. */
   return(1);
  }

  rread(header,7,1,fp);
  if(!strcmp(header,"ACDemo\n"))
  {
   rclose(fp);
   return(1);
  }

  if(!vxbcreate(vxnb,nsize,type))
  {
   rclose(fp);
   return(1);
  }

  memcpy(vxbuff[vxnb].data,header,7);
  fix=7;

  while(1)
  {
   nread=rread(vxbuff[vxnb].data+(nsize-nstep)*vxbuff[vxnb].framesize+fix,
                             1,vxbuff[vxnb].framesize*nstep-fix,fp);

   nread=(nread+fix)/vxbuff[vxnb].framesize;

   fix=0;

   if(nread<nstep)   /* we're going out at this point */
   {
    nsize=nsize-nstep+nread;
    vxbsize(vxnb,nsize);
    break;
   }

   if(!vxbsize(vxnb,nsize+nstep)) break;
   nsize+=nstep;
  }
  rclose(fp);
 }
 vxbupdatecurrent();

 if(!currentterminalopen) setterm(type==CEPT2FF?TERMMX:TERMVX);

 if(vxopen) vxbopen(vxnb);

 return(1);
}




/* current buffer setup, insert file */

int vxbinsertfile(char * name,int type)
{
 FILE * fp;

 int    nread;
 int    nstep=10;
 int    nsize=vxbuff[vxnb].noframes;
 char   header[16];
 char * data;
 int    fix;

 type=vxmaptypetosize(type);
 if(type!=vxbuff[vxnb].framesize) return(NOLOAD);

 if((fp=ropen(name,"rb"))==NULL) return(NOLOAD);

 rread(header,7,1,fp);
 if(!strcmp(header,"ACDemo\n"))
 {
  rclose(fp);
  return(1);
 }
 fix=7;

 while(1)
 {
  if(!vxbsize(vxnb,nsize+nstep)) break;
  nsize+=nstep;

  data=vxbuff[vxnb].data+(nsize-nstep)*vxbuff[vxnb].framesize;
  if(fix) memcpy(data,header,7);

  nread=rread(data+fix,1,vxbuff[vxnb].framesize*nstep-fix,fp);
  nread=(nread+fix)/vxbuff[vxnb].framesize;

  fix=0;

  if(nread<nstep)   /* we're going out at this point */
  {
   nsize=nsize-nstep+nread;
   vxbsize(vxnb,nsize);
   break;
  }
 }

 rclose(fp);

 vxbmod(vxnb);

 return(1);
}





/*****************************************************************************/
/* menu entry points, deal with current buffer */


/* someone clicks on new buffer on menu */

int vxnewbuffer(char * name)
{
 int len=strlen(name);

 if(len<=0 || len>10) 
 {
  errorbox("{VXBF04}"); /* Bad buffer name. */
  return(0);
 }

 vxnb=getnewvxb();

 if(vxbcreate(vxnb,0,vxframesize))
 {
  vxcbuff=vxnb;

  strcpy(vxbuff[vxnb].name,name);
  strcpy(vxbuff[vxnb].wname,name);

  vxbupdatecurrent();
  return(1);
 }
 else
  return(0);
}



/* someone clicks on show buffer on menu */

void vxshowbuffer(void)
{
 vxbopen(vxcbuff);
}



/* save the current buffer as a frame file */

int vxsavebuffersub(char * filename,int i)
{
 FILE * fp;

 if((fp=ropen(filename,"wb"))==NULL) return(0);

 rwrite(vxbuff[i].data,vxbuff[i].framesize,vxbuff[i].noframes,fp);

 savetypeclose(fp,filename);

 strcpy(vxbuff[i].name,filename);
 strcpy(vxbuff[i].wname,leaf(filename));

 refreshwindowtitle(vxbuff[i].handle);

 if(i==vxcbuff) vxbupdatecurrent();

 vxbuff[i].modded=0;

 return(1);
}


int vxsavebuffer(char * filename)
{
 return(vxsavebuffersub(filename,vxcbuff));
}


int vxsavembuffer(char * filename)
{
 return(vxsavebuffersub(filename,vxbmenu));
}



/* delete buffer i */

void vxdeletebuffern(int i,int check)
{
 int code;
 
 if(check && vxbuff[i].modded)
 {
  code=confirm(CONSDC,"{VXBF05}");/*Do you want to save modified buffer?*/
  if(code==1)
  {
   if(i==vxcbuff) opensave(SAVEVXBUFFFRAME);
   else           opensave(SAVEVXBUFFMFRAME);
  }
  if(code!=0) return;
 }

 if(vxbuff[i].handle) vxbclose(i);

 vxbtrash(i);

 if(i==vxcbuff) 
 {
  for(vxcbuff=0;vxcbuff<MAXBUFF;vxcbuff++) if(vxbuff[vxcbuff].inuse) break;
  if(vxcbuff>=MAXBUFF) vxcbuff=-1;
 }

 vxbupdatecurrent();
}


/* delete buffer off menu */

void vxdeletebuffer(void)
{
 vxdeletebuffern(vxcbuff,1);
}



/*****************************************************************************/


/* closes all buffer windows open on screen */

void vxbclosebuffers(void)
{
 int i;

 for(i=0;i<MAXBUFF;i++)
  if(vxbuff[i].inuse && vxbuff[i].handle) vxbclose(i);
}



/* return number of modded buffers */

int vxbunsaved(void)
{
 int i;
 int n=0;

 for(i=0;i<MAXBUFF;i++)
  if(vxbuff[i].inuse && vxbuff[i].modded) n++;

 return(n);
}



/* trash any buffers */

void vxbclearunsaved(void)
{
 int i;
 for(i=0;i<MAXBUFF;i++) if(vxbuff[i].inuse) vxdeletebuffern(i,0);
}



int vxclearbok(void)
{
 int n=vxbunsaved();

 if(n==1) return(confirm(CONDC,"{VXBF06}")!=1);
 else
 if(n>1) return(confirm(CONDC,"{VXBF07}")!=1);

 return(0);
}



void vxbuffboot(void)
{
 int i;

 for(i=0;i<MAXBUFF;i++)
 {
  vxbuff[i].vsc=NULL;
  vxbuff[i].data=NULL;
  vxbuff[i].handle=NULL;
  vxbuff[i].inuse=0;
  vxbuff[i].tools=0;
  vxbuff[i].thandle=NULL;
 }

 vxcbuff=-1;
 vxnobuffers=0;
}


/*****************************************************************************/
/* script language */


/* int vxbuffopen(char * filename) */
/* return buffer handle or 0 */

int vxbuffopen(int fp)
{
 char * filename=stringptr(stack[fp]);
 int    code;
 fstat  f;

 /* if it exists, then need file type and call usual load fn */

 code=fexists(filename);

 if(code==2) return(0);
 else
 if(code==1) 
 {
  if(stat(filename,&f)) return(0);
  if(vxbloadfile(filename,f.type))  return(vxnb+1);
  else                              return(0);
 }
 else
 {
  if(vxnewbuffer(leaf(filename)))
  {
   strcpy(vxbuff[vxnb].name,filename);
   return(vxnb+1);
  }
  else return(0);
 }
}



int vxbuffclose(int fp)
{
 int handle=stack[fp]-1;

 if(handle>=0 && handle<MAXBUFF && vxbuff[handle].inuse)
 {
  if(vxbuff[handle].modded) 
  {
   saveftype=vxmapsizetotype(vxbuff[handle].framesize);
   if(!vxsavebuffersub(vxbuff[handle].name,handle)) return(0);
   vxdeletebuffern(handle,1);
   return(1);
  }
 }
 return(0);
}


void vxbuffshow(int fp)
{
 int handle=stack[fp]-1;
 int show=stack[fp+1];

 if(handle>=0 && handle<MAXBUFF && vxbuff[handle].inuse)
 {
  if(show) vxbopen(handle);
  else     vxbclose(handle);
 }
}


int vxbuffseek(int fp)
{
 int handle=stack[fp]-1;
 int n=stack[fp+1];

 if(handle>=0 && handle<MAXBUFF && vxbuff[handle].inuse)
 {
  if(n<0) return(0);
  if(n>=vxbuff[handle].noframes) return(0);
  vxbuff[handle].current=n;
  vxbsetscreenr(handle);
  vxbwritecurrent(handle);
  return(1);
 }
 else return(0);
}


int vxbuffop(int fp)
{
 int handle=stack[fp]-1;
 int op=stack[fp+1];

 if(handle>=0 && handle<MAXBUFF && vxbuff[handle].inuse)
 {
  switch(op)
  {
   case 0: /* append */
          vxbcopy(handle);
          break;

   case 1: /* insert */
          vxbinsert(handle);
          break;

   case 2: /* over write */
          vxbreplace(handle);
          break;

   case 3: /* delete */
          vxbdelete(handle);
          break;

   case 4: /* paste */
          vxbpaste(handle);
          break;

   case 5: /* goto */
          vxbgoto(handle);
          break;
  }
  return(1);
 }
 else return(0);
}


void xsendframe(int fp)
{
 sendscreen();
 fp=0;
}

